#pragma once

#include <brpc/server.h>
#include <butil/logging.h>
#include <cctype>
#include <regex>

#include "etcd.hpp"
#include "logger.hpp"
#include "base.pb.h"
#include "user.pb.h"
#include "message.pb.h"
#include "friend.pb.h"

#include "utils.hpp"
#include "es_data.hpp"
#include "channel.hpp"
#include "mysql_chat_session_member.hpp"
#include "mysql_chat_session.hpp"
#include "mysql_friend_apply.hpp"
#include "mysql_relation.hpp"


 
namespace xu
{
    class FriendServicelmpl :public xu::FriendService
    {
    public:
        FriendServicelmpl(
        const std::string &user_service_name,
        const std::string &message_service_name,
        ServiceManage::ptr service_manage,
        std::shared_ptr<elasticlient::Client> es_client,
        std::shared_ptr<odb::mysql::database> mysql_client)
        :_user_service_name(user_service_name),
        _message_service_name(message_service_name),
        _service_manage(service_manage),
        _es_user(std::make_shared<ESUser>(es_client)),
        _manage_session(std::make_shared<ManageSession>(mysql_client)),
        _manage_chat_session(std::make_shared<ManageChatSession>(mysql_client)),
        _manage_friend(std::make_shared<ManageFriendApply>(mysql_client)),
        _manage_relation(std::make_shared<ManageRelation>(mysql_client))
        {}
        ~FriendServicelmpl(){}
        //获取好友列表
        virtual void GetFriendList(::google::protobuf::RpcController* controller,
                       const ::xu::GetFriendListReq* request,
                       ::xu::GetFriendListRsp* response,
                       ::google::protobuf::Closure* done) override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 获取请求中的用户 ID 
            std::string uid = request->user_id();

            // 2. 根据用户 ID，从数据库的好友关系表&用户表中取出该用户所有的好友简息
            auto res = _manage_relation->Friends(uid);
            if(res.empty())
            {
                response->set_success(true);
                return ;
            }
            std::unordered_set<std::string> user_ids(res.begin(),res.end());
            std::unordered_map<std::string, UserInfo> user_infos;
            bool ret = GetUserList(user_ids,user_infos);
            if(ret == false)
            {
                LOG_ERROR("获取好友信息失败");
                err_rsp("获取好友信息失败");
                return;
            }

            // 3. 组织响应，将好友列表返回给网关
            response->set_success(true);
            for(const auto & e : user_infos)
            {
                auto user_info = response->add_friend_list();
                user_info->CopyFrom(e.second);
            }
        }

        //好友删除
        virtual void FriendRemove(::google::protobuf::RpcController* controller,
                            const ::xu::FriendRemoveReq* request,
                            ::xu::FriendRemoveRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };


            // 1. 取出请求中的删除者 ID 和被删除者 ID
            std::string uid = request->user_id();
            std::string pid = request->peer_id();

            // 2. 从用户好友关系表中删除相关关系数据，从会话表中删除单聊会话，从会话成员表中删除会话成员信息
            bool ret = _manage_relation->Delete(uid,pid);
            if(ret == false)
            {
                LOG_ERROR("好友关系表删除失败 {} - {}",uid,pid);
                err_rsp("好友关系表删除失败");
                return;
            }

            ret = _manage_chat_session->Delete(uid,pid);
            if(ret == false)
            {
                LOG_ERROR("会话表或会话成员表删除失败 {} - {}",uid,pid);
                err_rsp("会话表或会话成员表删除失败");
                return;
            }

            // 3. 组织响应，返回给网关
            response->set_success(true);

        }

        //添加好友--发送好友申请
        virtual void FriendAdd(::google::protobuf::RpcController* controller,
                            const ::xu::FriendAddReq* request,
                            ::xu::FriendAddRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 取出请求中的请求者 ID，和被请求者 ID
            std::string uid = request->user_id();
            std::string rid = request->respondent_id();

            // 2. 判断两人是否已经是好友
            bool ret = _manage_relation->Exists(uid,rid);
            if(ret)
            {
                LOG_ERROR("他们已经是好友了 {} - {}",uid,rid);
                err_rsp("他们已经是好友了");
                return;
            }
            // 3. 判断该用户是否已经申请过好友关系
            ret = _manage_friend->Exists(uid,rid);
            if(ret)
            {
                LOG_ERROR("已经发送过好友申请了 {} - {}",uid,rid);
                err_rsp("已经发送过好友申请了");
                return;
            }
            // 4. 向好友申请事件表中，新增申请信息
            std::string eid = uuid();
            FriendApply ev(eid,uid,rid);
            ret = _manage_friend->Insert(ev);

            // 5. 组织响应，将事件 ID 信息响应给网关
            response->set_success(true);
            response->set_notify_event_id(eid);

        }

        //好友申请的处理
        virtual void FriendAddProcess(::google::protobuf::RpcController* controller,
                            const ::xu::FriendAddProcessReq* request,
                            ::xu::FriendAddProcessRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 取出请求中的申请人 ID，和被申请人 ID，以及处理结果
            std::string uid = request->user_id();
            std::string aid = request->apply_user_id();
            bool res =  request->agree();

            // 2. 根据两人 ID 在申请事件表中查询判断是否存在申请事件
            bool ret = _manage_friend->Exists(aid,uid);
            if(!ret)
            {
                LOG_ERROR("没有发送过好友申请 {} - {}",uid,aid);
                err_rsp("没有发送过好友申请");
                return;
            }
            // 3. 判断两人是否已经是好友（互相加好友的情况）
            ret = _manage_relation->Exists(uid,aid);
            if(ret)
            {
                LOG_ERROR("他们已经是好友了 {} - {}",uid,aid);
                err_rsp("他们已经是好友了");
                return;
            }

            // 4. 不管拒绝还是同意，删除申请事件表中的事件信息（该事件处理完毕）
            ret = _manage_friend->Delete(aid,uid);
            if(ret == false)
            {
                LOG_ERROR("删除请求好友事件失败 {} - {}",uid,aid);
                err_rsp("删除请求好友事件失败");
                return;
            }
            // 5. 若同意申请，则向用户关系表中添加好友关系数据，向会话表中新增会话信息，向会话成员表中新增成员信息
            std::string ssid;
            if(res)
            {
                ret = _manage_relation->Insert(uid,aid);
                if(ret == false)
                {
                    LOG_ERROR("添加好友关系表失败 {} - {}",uid,aid);
                    err_rsp("添加好友关系表失败");
                    return;
                }
                ssid = uuid();
                ChatSession cs(ssid,"",ChatSessionType::SINGLE);
                ret = _manage_chat_session->Insert(cs);
                if(ret == false)
                {
                    LOG_ERROR("添加好友会话表失败 {} - {}",uid,aid);
                    err_rsp("添加好友会话表失败");
                    return;
                }


                std::vector<Session> session_list({Session(ssid,uid),Session(ssid,aid)});
                ret = _manage_session->Insert(session_list);
                if(ret == false)
                {
                    LOG_ERROR("添加好友会话成员表失败 {} - {}",uid,aid);
                    err_rsp("添加好友会话成员表失败");
                    return;
                }   
            }
            // 6. 组织响应，将新生成的会话 ID 响应给网关
            response->set_new_session_id(ssid);
            response->set_success(true);
        }

        //好友搜索
        virtual void FriendSearch(::google::protobuf::RpcController* controller,
                            const ::xu::FriendSearchReq* request,
                            ::xu::FriendSearchRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 取出请求中的用户 ID，和搜索关键字
            std::string uid = request->user_id();
            std::string search_key = request->search_key();

            // 2. 从好友关系表中取出该用户所有好友 ID
            auto res = _manage_relation->Friends(uid);
            res.push_back(uid);
            // 3. 根据关键字从 ES 服务器中进行用户搜索，搜索的时候需要将关键字作为用户 ID/
            // 手机号/昵称的搜索关键字进行搜索，且需要根据自己的 ID 和好友 ID 过滤掉自己和自
            // 己的好友。
            auto user_list = _es_user->Search(search_key,res);
            if(user_list.empty())
            {
                response->set_success(true);
                return;
            }
            // 4. 根据搜索到的用户简息中的头像 ID
            std::unordered_set<std::string> user_ids;
            for(auto &e : user_list)
            {
                LOG_DEBUG("es查找到的用户id : {}" , e.user_id());
                user_ids.insert(e.user_id());
            }
            LOG_DEBUG("--------------");
            std::unordered_map<std::string, UserInfo> user_infos;
            bool ret = GetUserList(user_ids,user_infos);
            if(ret == false)
            {
                LOG_ERROR("获取用户信息失败");
                err_rsp("获取用户信息失败");
                return;
            }

            // 5. 组织响应，将搜索到的用户列表响应给网关
            response->set_success(true);
            for(const auto & e : user_infos)
            {
                auto user_info = response->add_user_info();
                user_info->CopyFrom(e.second);
            }
        }

        //会话列表获取
        virtual void GetChatSessionList(::google::protobuf::RpcController* controller,
                            const ::xu::GetChatSessionListReq* request,
                            ::xu::GetChatSessionListRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 从请求中取出用户 ID
            std::string uid = request->user_id();

            // 2. 根据用户 ID，从会话表&会话成员表&用户表中取出好友的单聊会话列表（会话 ID，
            // 好友用户 ID，好友昵称，好友头像 ID），并组织会话信息结构对象
            // a. 单聊会话中，对方的昵称就是会话名称，对方的头像就是会话头像，会话类
            // 型为单聊类型
            auto res1 = _manage_chat_session->GetSingleChatSession(uid);
            std::unordered_set<std::string> user_ids;
            for(const auto &e : res1)
            {
                user_ids.insert(e.friend_id);
            }
            std::unordered_map<std::string, UserInfo> user_infos;
            bool ret = GetUserList(user_ids,user_infos);
            if(ret == false)
            {
                LOG_ERROR("获取申请用户信息失败");
                err_rsp("获取申请用户失败");
                return;
            }

            // 3. 根据单聊会话 ID，从消息存储子服务获取会话的最后一条消息
            for(const auto &e : res1)
            {
                auto info = response->add_chat_session_info_list();
                info->set_single_chat_friend_id(e.friend_id);
                info->set_chat_session_id(e.chat_session_id);
                info->set_chat_session_name(user_infos[e.friend_id].nickname());
                info->set_avatar(user_infos[e.friend_id].avatar());
                MessageInfo meg_info;
                ret = GetMessage(e.chat_session_id,meg_info);
                if(ret == false)
                {
                    LOG_ERROR("获取消息信息失败");
                    err_rsp("获取消息信息失败");
                    return;
                }
                info->mutable_prev_message()->CopyFrom(meg_info);
            }

            // 6. 根据用户 ID，从会话表&会话成员表中取出群聊会话列表（会话 ID，会话名称）
            auto res2 = _manage_chat_session->GetGroupChatSession(uid);
            for(const auto &e : res2)
            {
                auto info = response->add_chat_session_info_list();
                info->set_chat_session_id(e.chat_session_id);
                info->set_chat_session_name(e.chat_session_name);
                MessageInfo meg_info;
                ret = GetMessage(e.chat_session_id,meg_info);
                if(ret == false)
                {
                    LOG_ERROR("获取消息信息失败");
                    err_rsp("获取消息信息失败");
                    return;
                }
                info->mutable_prev_message()->CopyFrom(meg_info);
            }

            response->set_success(true);
        }

        ////创建会话
        virtual void ChatSessionCreate(::google::protobuf::RpcController* controller,
                            const ::xu::ChatSessionCreateReq* request,
                            ::xu::ChatSessionCreateRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 从请求中取出用户 ID 与会话名称，以及会话的成员 ID 列表
            std::string uid = request->user_id();
            std::string chat_session_name = request->chat_session_name();
            std::vector<std::string> member_id_list;
            for(int i = 0; i < request->member_id_list_size(); ++i)
            {
                member_id_list.push_back(request->member_id_list(i));                
            }

            // 2. 生成会话 ID，并向会话表中新增会话信息数据，会话为群聊会话（单聊会话是同
            // 意好友申请的时候创建的）
            std::string ssid = uuid();
            ChatSession cs(ssid,chat_session_name,ChatSessionType::GROUP);
            bool ret = _manage_chat_session->Insert(cs);
            if(ret == false)
            {
                LOG_ERROR("插入会话失败");
                err_rsp("插入会话失败");
                return;
            }

            // 3. 向会话成员表中新增所有的成员信息
            std::vector<Session> members;
            for(const auto &e : member_id_list)
            {
                members.push_back(Session(ssid,e));
            }
            ret = _manage_session->Insert(members);
            if(ret == false)
            {
                LOG_ERROR("插入会话成员失败");
                err_rsp("插入会话成员失败");
                return;
            }
            // 4. 组织响应，将组织好的会话信息响应给网关。
            response->mutable_chat_session_info()->set_chat_session_id(ssid);
            response->mutable_chat_session_info()->set_chat_session_name(chat_session_name);
            response->set_success(true);
        }

        ////获取会话成员列表
        virtual void GetChatSessionMember(::google::protobuf::RpcController* controller,
                            const ::xu::GetChatSessionMemberReq* request,
                            ::xu::GetChatSessionMemberRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 取出请求中用户 ID，和会话 ID
            std::string uid = request->user_id();
            std::string ssid = request->chat_session_id();

            // 2. 根据会话 ID，从会话成员表&用户表中取出所有的成员用户信息
            auto res = _manage_session->SelectUserId(ssid);

            std::unordered_set<std::string> user_ids(res.begin(),res.end());
            std::unordered_map<std::string, UserInfo> user_infos;
            bool ret = GetUserList(user_ids,user_infos);
            if(ret == false)
            {
                LOG_ERROR("获取好友信息失败");
                err_rsp("获取好友信息失败");
                return;
            }

            response->set_success(true);

            // 4. 组织响应，将会话的成员用户信息列表响应给网关
            for(const auto & e : user_infos)
            {
                auto user_info = response->add_member_info_list();
                user_info->CopyFrom(e.second);
            }
        }

        //获取待处理的，申请自己好友的信息列表
        virtual void GetPendingFriendEventList(::google::protobuf::RpcController* controller,
                            const ::xu::GetPendingFriendEventListReq* request,
                            ::xu::GetPendingFriendEventListRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 取出请求中的用户 ID
            std::string uid = request->user_id();

            // 2. 根据用户 ID，从申请事件表&用户表中找到该用户所有状态为 PENDING 的待处
            // 理事件关联申请人用户简息
            auto res = _manage_friend->ApplyUsers(uid);
            
            // 3. 根据申请人用户头像 ID，从文件存储子服务器获取所有用户头像信息，组织用户
            // 信息结构
            std::unordered_set<std::string> user_ids(res.begin(),res.end());
            std::unordered_map<std::string, UserInfo> user_infos;
            bool ret = GetUserList(user_ids,user_infos);
            if(ret == false)
            {
                LOG_ERROR("获取申请用户信息失败");
                err_rsp("获取申请用户失败");
                return;
            }

            // 4. 组织响应，将申请事件列表响应给网关
            response->set_success(true);
            for(const auto & e : user_infos)
            {
                auto event = response->add_event();
                event->mutable_sender()->CopyFrom(e.second);
            }
        }
    private:
        bool GetUserList(const std::unordered_set<std::string> user_ids, 
            std::unordered_map<std::string, UserInfo> & res)
        {
            auto channel = _service_manage->Choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("信道获取失败");
                return false;
            }

            xu::UserService_Stub stub(channel.get());
            xu::GetMultiUserInfoReq req;
            xu::GetMultiUserInfoRsp rsp;
            brpc::Controller cntl;

            req.set_request_id(uuid());
            for(const auto &uid : user_ids)
            {
                LOG_DEBUG("uid : {}" , uid);
                req.add_users_id(uid);
            }

            stub.GetMultiUserInfo(&cntl,&req,&rsp,nullptr);

            if(cntl.Failed() || rsp.success() == false)
            {
                LOG_ERROR("获取用户信息请求失败");
                return false;
            }

            auto mp = rsp.users_info();
            for(const auto & e: mp)
            {
                res.insert(std::make_pair(e.first,e.second));
            }
            return true;
        }

        bool GetMessage(const std::string & ssid, MessageInfo &res)
        {
            auto channel = _service_manage->Choose(_message_service_name);
            if (!channel) {
                std::cout << "获取消息信道失败！" << std::endl;
                return false;
            }
            xu::MsgStorageService_Stub stub(channel.get());
            xu::GetRecentMsgReq  req;
            xu::GetRecentMsgRsp  rsp;
            req.set_request_id(uuid());
            req.set_chat_session_id(ssid);
            req.set_msg_count(1);
            brpc::Controller cntl;
            stub.GetRecentMsg(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed() == true || rsp.success() == false)
            {
                std::cout<<"请求失败" <<std::endl;
            }
            if(rsp.msg_list_size() > 0)
            {
                res = rsp.msg_list(0);
            }
            return true;
        }
    private:
        std::string _user_service_name;
        std::string _message_service_name;
        ServiceManage::ptr _service_manage;
        ESUser::ptr _es_user;                           //es搜索引擎
        ManageSession::ptr _manage_session;
        ManageChatSession::ptr _manage_chat_session;
        ManageFriendApply::ptr _manage_friend;
        ManageRelation::ptr _manage_relation;
    };

    class FriendServer
    {
    public:
        using ptr = std::shared_ptr<FriendServer>;
        FriendServer(
            ServiceManage::ptr service_manage,
            Discovery::ptr discovery,
            Registration::ptr registration,
            std::shared_ptr<brpc::Server> server,
            std::shared_ptr<elasticlient::Client> es_client,
            std::shared_ptr<odb::mysql::database> mysql_client)
            :_discovery(discovery),
            _service_manage(service_manage),
            _registration(registration),
            _server(server),
            _es_client(es_client),
            _mysql_client(mysql_client)
        {}
        ~FriendServer(){}
        void Start()
        {
            _server->RunUntilAskedToQuit();
        }
    private:
        ServiceManage::ptr _service_manage;                 //服务发现信道管理
        Discovery::ptr _discovery;                          //服务发现
        Registration::ptr _registration;                    //etcd注册
        std::shared_ptr<brpc::Server> _server;              //rpc注册调用
        std::shared_ptr<elasticlient::Client> _es_client;   //es搜索引擎客户端
        std::shared_ptr<odb::mysql::database> _mysql_client;//mysql客户端
    };

    class FriendServerBuilder
    {
    public:
        FriendServerBuilder(){}
        ~FriendServerBuilder(){}

        //构造服务发现信道
        void SetServiceManage(const std::string &user_service_name,const std::string &message_service_name)
        {
            _user_service_name = user_service_name;
            _message_service_name = message_service_name;
            //1.创建对象
            _service_manage = std::make_shared<xu::ServiceManage>();
            //2.添加发现服务
            _service_manage->AddFollow(_user_service_name);
            _service_manage->AddFollow(_message_service_name);
        }
        //构造etcd发现
        void SetDiscovery(const std::string &etcd_host,const std::string &base_service)
        {
            if(!_service_manage)
            {
                LOG_ERROR("ServiceManage未初始化");
                return ;
            }
            //1.绑定回调函数
            auto put_cb = std::bind(&xu::ServiceManage::onServiceOnline, _service_manage.get(), std::placeholders::_1, std::placeholders::_2);
            auto del_cb = std::bind(&xu::ServiceManage::onServiceOffline, _service_manage.get(), std::placeholders::_1, std::placeholders::_2);
            //2. 构造服务发现对象
           _discovery = std::make_shared<xu::Discovery>(etcd_host,base_service, put_cb, del_cb);
        }
        //构造etcd注册
        void SetRegistration(const std::string &host,const std::string &service_name,
            const std::string &access_host)
        {
            _registration = std::make_shared<Registration>(host);
            _registration->AddKV(service_name,access_host);
        }

        //构造Es客户端
        void SetEsClient(const std::vector<std::string> &host_list)
        {
            _es_client = ESClientFactory::Create(host_list);
        }

        //构造Mysql客户端
        void SetMysqlClient(const std::string & user,
            const std::string &pswd,const std::string &db_name,
            const std::string &host,const std::string &cset)    
        {
            _mysql_client = MysqlClientFactory::Create(user,pswd,db_name,host,cset);
        }
       
        //构造rpc注册调用
        void SetRpcServer(uint16_t port, int32_t timeout, uint8_t num_threads)
        {
            if(!_service_manage)
            {
                LOG_ERROR("ServiceManage未初始化");
                return ;
            }

            if(!_es_client)
            {
                LOG_ERROR("EsClient未初始化");
                return ;
            }

            if(!_mysql_client)
            {
                LOG_ERROR("MysqlClient未初始化");
                return ;
            }

            _server = std::make_shared<brpc::Server>();

            FriendServicelmpl *friend_service = new  FriendServicelmpl(_user_service_name,_message_service_name,
             _service_manage,_es_client, _mysql_client);
            _server->AddService(friend_service,brpc::ServiceOwnership::SERVER_OWNS_SERVICE);

            brpc::ServerOptions options;
            options.idle_timeout_sec = timeout;
            options.num_threads = num_threads;

            _server->Start(port, &options);
        }

        //构造FriendServer
        FriendServer::ptr Build()
        {
            if(!_registration)
            {
                LOG_ERROR("Registration未初始化");
                return FriendServer::ptr();
            }

             if(!_discovery)
            {
                LOG_ERROR("Discovery未初始化");
                return FriendServer::ptr();
            }

            if(!_server)
            {
                LOG_ERROR("RpcServer未初始化");
                return FriendServer::ptr();
            }

            auto res = std::make_shared<FriendServer>(_service_manage,_discovery,_registration,
            _server,_es_client,_mysql_client);
            return res;
        }

    private:
        std::string _user_service_name;
        std::string _message_service_name;
        ServiceManage::ptr _service_manage;                 //服务发现信道管理
        Discovery::ptr _discovery;                          //服务发现
        Registration::ptr _registration;                    //etcd注册
        std::shared_ptr<elasticlient::Client> _es_client;   //es搜索引擎客户端
        std::shared_ptr<odb::mysql::database> _mysql_client;//mysql客户端
        std::shared_ptr<brpc::Server> _server;              //rpc注册调用     
    };
}
